
#ifndef __TVECTOR__
#define __TVECTOR__


#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <tchar.h>
#include <assert.h>
#include <typeinfo.h>


template <typename T>
class	TVector
{
private:
	T	*m_pData;
	int	m_nLength;

public:
	TVector()
	{
		m_nLength = 0;
		m_pData = NULL;
	}
	TVector(int nLength)
	{
		m_nLength = 0;
		m_pData = NULL;
		alloc(nLength);
	}
	TVector(const TVector &v)
	{
		m_nLength = 0;			//called only in definition
		m_pData = NULL;
		alloc(v.m_nLength);
		memcpy(m_pData, v.m_pData, sizeof(T) * m_nLength);
	}
	TVector(T *data, int nLength)
	{
		alloc(nLength);
		memcpy(m_pData, data, sizeof(T) * nLength);
	}
	~TVector()
	{
		free();
	}	
	int load(TCHAR *file, TCHAR* type = _T("BIN"))
	{
		FILE	*fp;
		int		i;
		T		value;
		float	fvalue;
		if(stricmp(type, _T("TXT")) == 0)
		{
			if((fp = _tfopen(file, _T("rt"))) == NULL)
				return 0;		
			_ftscanf(fp, _T("%d"), &m_nLength);
			resize(m_nLength);
			for(i = 0; i < m_nLength; i++)
			{
				if(typeid(T) == typeid(double))
				{
					_ftscanf(fp, _T("%f"), &fvalue);
					value = fvalue;
				}
				else if(typeid(T) == typeid(float)) //float
					_ftscanf(fp, _T("%f"), &value);
				else
					_ftscanf(fp, _T("%d"), &value);
				m_pData[i] = value;
			}
		}
		else if(stricmp(type, _T("BIN")) == 0)
		{
			if((fp = _tfopen(file, _T("rb"))) == NULL)
				return 0;
			fread(&i, sizeof(int), 1, fp);
			alloc(i);
			fread(&i, sizeof(int), 1, fp);
			assert(sizeof(T) == i);
			fread(m_pData, sizeof(T) * m_nLength, 1, fp);
		}
		else
		{
			_tprintf(_T("load vector as UNKNOWN format.\n"));
		}
		fclose(fp);
		return 1;
	}
	int load(T* data, int len)
	{
		alloc(len);
		memcpy(m_pData, data, len * sizeof(T));
		return 1;
	}
	int save(TCHAR *file, TCHAR* type = _T("BIN"))
	{
		FILE*fp;		
		int	i;		
		if(stricmp(type, _T("TXT")) == 0)
		{
			if((fp = _tfopen(file, _T("wt"))) == NULL)
				return 0;
			_ftprintf(fp, _T("%d\n"), m_nLength);
			for(i = 0; i < m_nLength; i++)
			{
				if(typeid(T) == typeid(double))		// double
					_ftprintf(fp, _T("%.6g "), m_pData[i]);
				else if(typeid(T) == typeid(float)) //float
					_ftprintf(fp, _T("%.5f "), m_pData[i]);
				else if(typeid(T) == typeid(int))
					_ftprintf(fp, _T("%d "), m_pData[i]);
			}
		}
		else if(stricmp(type, _T("BIN")) == 0)
		{
			if((fp = _tfopen(file, _T("wb"))) == NULL)
				return 0;
			fwrite(&m_nLength, sizeof(int), 1, fp);
			i = sizeof(T);
			fwrite(&i, sizeof(i), 1, fp);
			fwrite(m_pData, sizeof(T) * m_nLength, 1, fp);
		}
		else
		{
			_tprintf(_T("saving vector as UNKNOWN format.\n"));
		}
		fclose(fp);
		return 1;
	}
	void print()
	{
		for(int i = 0; i < m_nLength; i++)
		{
			if(typeid(T) == typeid(double) || typeid(T) == typeid(float))
				printf("%f\t", m_pData[i]);
			else
				printf("%d\t", m_pData[i]);
		}
		printf("\n");
	}
	int alloc(int nLength = 0)
	{
		free();
		if(nLength != 0)
		{
			m_pData = (T *) GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(T) * nLength);
			if(m_pData == NULL)
				return -1;
		}
		else
			m_pData = NULL;
		m_nLength = nLength;
		return 1;
	}
	int resize(int nLength)
	{
		free();
		return alloc(nLength);
	}
	void free()
	{
		if(m_pData && m_nLength)
			GlobalFree(m_pData);
		m_pData = NULL;
		m_nLength = 0;
	}	
	int append(T value)
	{
		if(m_pData == NULL)
		{
			alloc(1);
			m_pData[0] = value;
		}
		else
		{
			T	*pValues	= (T *) GlobalAlloc(GMEM_FIXED, sizeof(T) * (m_nLength + 1));
			if(pValues == NULL)
				return -1;
			memcpy(pValues, m_pData, sizeof(T) * m_nLength);
			pValues[m_nLength] = value;
			m_nLength++;
			GlobalFree(m_pData);
			m_pData = pValues;
		}
		return 0;
	}
	int insert(T value, int before = -1) //before = -1, insert at tail
	{
		if(before == -1)
			append(value);
		else if(before < m_nLength)
		{
			T	*pValues	= (T *) GlobalAlloc(GMEM_FIXED, sizeof(T) * (m_nLength + 1));
			if(pValues == NULL)
				return -1;
			memcpy(pValues, m_pData, sizeof(T) * before);
			pValues[before] = T;
			memcpy(pValues + before + 1, m_pData + before, sizeof(T) * (m_nLength - before));
			m_nLength++;
			GlobalFree(m_pData);
			m_pData = pValues;
		}
		else
			return -2;
		return 0;
	}
	int remove(int pos)
	{
		if(pos < m_nLength)
		{
			for(int i = pos + 1; i < m_nLength; i++)
				m_pData[i - 1] = m_pData[i];
			m_nLength--;
			return 0;
		}
		return -2;
	}
	int remove(int s, int e) //include m_pData[e]
	{
		if(s >= m_nLength || e >= m_nLength)
			return 0;
		if(e == -1)
			e = m_nLength;
		if(m_nLength - e + s > 0)
		{
			T	*pValues = (T *) GlobalAlloc(GMEM_FIXED, sizeof(T) * (m_nLength - e + s));
			if(pValues == NULL)
				return -1;
			memcpy(pValues, m_pData, sizeof(T) * s);
			if(e < m_nLength)
			{
				memcpy(pValues + s, m_pData + e + 1, sizeof(T) * (m_nLength - e - 1));
				m_nLength = m_nLength - e + s - 1;
			}
			else
				m_nLength = s;
			GlobalFree(m_pData);
			m_pData = pValues;
		}
		else
			free();
		return 0;
	}
	static TVector ones(int n)
	{
		TVector	a;
		a.alloc(n);
		for(int i = 0; i < n; i++)
			a[i] = 1;
		return a;
	}
	T * data()
	{
		return m_pData;
	}
	int size()
	{
		return m_nLength;
	}
	T & operator[](int i)
	{
		return m_pData[i];
	}
	void operator=(const TVector &v)
	{
		free();
		alloc(v.m_nLength);
		memcpy(m_pData, v.m_pData, sizeof(T) * m_nLength);
	}
	TVector operator*(T k)
	{
		TVector	B;
		B.alloc(m_nLength);
		for(int i = 0; i < m_nLength; i++)
			B.m_pData[i] *= k;
		return B;
	}
	TVector operator+(TVector &v)
	{
		TVector	B;
		B.alloc(m_nLength);
		for(int i = 0; i < m_nLength; i++)
			B.m_pData[i] = m_pData[i] + v.m_pData[i];
		return B;
	}
	TVector operator-(TVector &v)
	{
		TVector	B;
		B.alloc(m_nLength);
		for(int i = 0; i < m_nLength; i++)
			B.m_pData[i] = m_pData[i] - v.m_pData[i];
		return B;
	}
	T operator*(TVector &v)		//inner product
	{
		T	inner	= 0;		
		for(int i = 0; i < m_nLength; i++)
			inner += m_pData[i] * v.m_pData[i];
		return inner;
	}
	int operator==(TVector &v)
	{
		if(m_nLength != v.m_nLength)
			return 0;
		for(int i = 0; i < m_nLength; i++)
			if(m_pData[i] != v[i])
				return 0;
		return 1;
	}
	int operator!=(TVector &v)
	{
		return *this == v;
	}
	TVector crop(int s, int e)
	{
		TVector	B;
		assert(s < e);
		B.alloc(e - s);
		memcpy(B.m_pData, m_pData + s, (e - s) * sizeof(T));
		return B;
	}	
	T sum()
	{
		T	m	= 0;
		for(int i = 0; i < m_nLength; i++)
			m += m_pData[i];
		return m;
	}
	void zero(int s = 0, int e = -1)
	{
		if(e == -1)
			memset(m_pData, 0, sizeof(T) * m_nLength);
		else if(s < e)
		{
			for(int i = s; i < e; i++)
				m_pData[i] = 0;
		}
	}
	static TVector<int> randperm(int n, int k)
	{
		TVector<int>	perm;
		perm.alloc(n);
		srand(GetTickCount());
		for(int i = 0; i < n; i++)
			perm[i] = rand() % k;
		//perm.sort();
		return perm;
	}
	static TVector<int> randperm(int n)
	{
		return randperm(n, n);
	}
	static int qsort_a_compare(const void *p, const void *q)
	{
		T	v1, v2;
		v1 = *((T *) p); v2 = *((T *) q);
		if(v1 < v2)
			return -1;
		else if(v1 > v2)
			return 1;
		return 0;
	}
	static int qsort_d_compare(const void *p, const void *q)
	{
		T	v1, v2;
		v1 = *((T *) p); v2 = *((T *) q);
		if(v1 < v2)
			return 1;
		else if(v1 > v2)
			return -1;
		return 0;
	}
	void sort(int direction = 1) //ascend
	{
		if(direction == 1)
			qsort(m_pData, m_nLength, sizeof(T), qsort_a_compare);
		else
			qsort(m_pData, m_nLength, sizeof(T), qsort_d_compare);
	}
	T	mmax(int* index = NULL)
	{
		int i, k = 0;
		T   max = m_pData[0];
		for(i = 0; i < m_nLength; i++)
		{
			if(m_pData[i] > max)
			{
				k = i;
				max = m_pData[i];
			}
		}
		if(index)
			*index = k;
		return max;
	}
	T	mmin(int* index = NULL)
	{
		int i, k = 0;
		T   min = m_pData[0];
		for(i = 0; i < m_nLength; i++)
		{
			if(m_pData[i] < min)
			{
				k = i;
				min = m_pData[i];
			}
		}
		if(index)
			*index = k;
		return min;
	}
};

#endif